A common activity performed by computer programs is to initialize a data item. For example, some high level programming languages are “object oriented” in that functionality of a program may be implemented in objects created from a class. As a program executes, the first time the program uses an object, a function or other program code initializes the object. As used herein, the term “initialize” or “initialization” refers to the process of allocating resources to a data item, such as an object. By way of example only, if a program creates a “file” object, the initialization process may include, but is not limited to, allocating memory to the file object, setting object specific variables, obtaining a file handle used to reference the file object, and the like.
In some instances, the process of initializing a data item, such as an object, is resource intensive. As a result, modern computer systems are typically configured to defer initialization until such time that a program will access the resources allocated to the object. Moreover, once an object has been initialized, information used to access or call the initialized object is “cached” so that subsequent calls to the object may be handled quickly without initialization being repetitively performed.
However, deferring initialization of a data item, such as an object, introduces potential error sources into a program that executes in any multi-threaded environment. In this regard, to overcome the deficiencies associated with previous generations of computers, modern operating systems have been created that are multi-threaded. A thread is the basic unit used by an operating system to allocate processor time and may include any part of a program's code, including parts currently being executed by another thread. Thus, as used herein, “multi-threaded” refers to the technique implemented by modern operating systems to alternate between different parts of a program (e.g., threads). As each thread completes executing, the processor is allocated to another thread. In a computer with one processor, the extraordinary speed of the processor provides the illusion that programs and their associated threads execute simultaneously. Multi-threaded operating systems increase the amount of work a computer system is able to accomplish because most programs do not require that threads continuously execute. For example, periodically, a thread “blocks” or stops executing and waits while a slow resource completes a data transfer or while another thread is using a resource it needs. When one thread must wait, multi-threaded environments allow another thread to execute, thus taking advantage of processor cycles that would otherwise be wasted.
While a multi-threaded operating system allocates resources efficiently, a potential error source arises as two or more threads may be configured to concurrently initialize the same data item (e.g., object). In some systems, a program developer may be required to synchronize the initialization of an object using a synchronization construct such as, but not limited to, a semaphore, condition variable, spinlock, etc. Synchronization constructs provide the ability for one thread to voluntarily stop executing or “sleep” and wait until another thread performs an operation. However, using a synchronization construct requires developers to carefully consider synchronization issues when developing a program. For example, the way in which a synchronization construct is implemented may be dependent on the computer platform in which a program will execute.